package evolution.individual;

import java.util.Arrays;

import evolution.problem.FitnessFunction;

/**
 * Class represents individual in real-coded representation. Note: this class
 * has a natural ordering that is inconsistent with equals.
 */
public class RealCodedIndividual implements Individual {

	protected double[] chromosome = null;
	protected double fitness = 0.0;
	protected boolean fitnessCalculated = false;
	protected FitnessFunction fitnessFunction;

	@Override
	public double[] getChromosome() {
		return chromosome;
	}

	@Override
	public void setChromosome(double[] chromosome) {
		this.chromosome = chromosome;
	}

	@Override
	public double getFitness() {
		if (!fitnessCalculated) {
			fitness = fitnessFunction.getValue(chromosome);
			fitnessCalculated = true;
		}
		return fitness;
	}

	@Override
	public void setFitness(double fitness) {
		this.fitness = fitness;
		fitnessCalculated = true;
	}

	@Override
	public FitnessFunction getFitnessFunction() {
		return fitnessFunction;
	}

	@Override
	public void setFitnessFunction(FitnessFunction fitnessFunction) {
		this.fitnessFunction = fitnessFunction;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(chromosome);
		long temp;
		temp = Double.doubleToLongBits(getFitness());
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RealCodedIndividual other = (RealCodedIndividual) obj;
		if (!Arrays.equals(chromosome, other.chromosome))
			return false;
		if (Double.doubleToLongBits(getFitness()) != Double
				.doubleToLongBits(other.getFitness()))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return Arrays.toString(chromosome) + " " + getFitness();
	}

	@Override
	public int compareTo(Individual other) {
		return Double.compare(getFitness(), other.getFitness());
	}

	@Override
	public RealCodedIndividual clone() {
		RealCodedIndividual clone = null;
		try {
			clone = (RealCodedIndividual) super.clone();
		} catch (CloneNotSupportedException ignored) {
		}

		clone.setChromosome(chromosome.clone());
		return clone;
	}
}
